﻿using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Ys.Base.Common
{
    /// <summary>
    /// 上传文件实体
    /// </summary>
    public class PostFileListEntity {
       
        /// <summary>
        /// 文件数据流
        /// </summary>
        public System.IO.Stream FileValue { get; set; } 
        /// <summary>
        /// 文件名称 包含拓展名
        /// </summary>
        public string FileName { get; set; }
        /// <summary>
        /// 拓展名
        /// </summary>
        public string GetExtension { get {
              return FileName.Split('.').Length == 2? FileName.Split('.')[1]:"";
                }
            } 
    }

    public enum YsPsotType {
        /// <summary>
        /// 提交Json数据模式 application/json
        /// </summary>
        [EnumText("提交Json数据模式 application/json")]
        Json = 1,
        /// <summary>
        /// 提交FormData multipart/form-data表单数据模式
        /// </summary>
        [EnumText("提交表单数据模式 multipart/form-data")]
        Form = 2,
        /// <summary>
        /// 提交application/x-www-form-urlencoded模式提交 
        /// </summary>
        [EnumText("提交表单数据模型 application/x-www-form-urlencoded")]
       Urlencoded=3

    }

    /// <summary>
    /// Http操作类型  post get
    /// </summary>
  public  class HttpHelp
    {


        #region Post

        /// <summary>
        /// Post请求 默认Json Post提交
        /// </summary>
        /// <param name="PostData">Json时用对象， form模式用 Dictionary<string, string> form支持 a=1&b=2字符串和对象模式 </param>
        /// <param name="RequestUrl">请求地址</param>
        /// <param name="postType">提交数据模式 默认json模式</param>
        /// <paramref name="FileList">提交的文件数据流</paramref>
        /// <param name="Token">token</param>
        /// <param name="TimeOut">超时时间 秒 默认300</param>
        /// <param name="JsonNotWebOption"> 提交的Json数据序列化是否和model一致 True 时候会采用小驼峰格式方式提交 False 对象原始大小写格式</param>
        /// <returns></returns>
        public static async Task<string> Post<T>(T PostData, string RequestUrl,YsPsotType postType= YsPsotType.Json,List<PostFileListEntity> FileList=null, string Token = null,int TimeOut=300,bool JsonNotWebOption = true)
        {

            var html = "";
            try
            {
                switch (postType)
                {
                    case YsPsotType.Json:
                        html = await PostJson(PostData, RequestUrl, Token,TimeOut, JsonNotWebOption: JsonNotWebOption);
                        break;

                    case YsPsotType.Form:
                       
                        html = await PostForm(_FormDataFormat(PostData), RequestUrl, FileList, Token,TimeOut);
                        break;
                    case YsPsotType.Urlencoded:
                        html = await PostFormUrlencoded(_FormDataFormat(PostData),RequestUrl,Token,TimeOut);
                        break;
                }
            }
            catch {
                html = null;
            }
            return html;
        }

        /// <summary>
        /// 格式化formdata数据字典
        /// </summary>
        /// <param name="PostData"></param>
        /// <returns></returns>
        private static Dictionary<string, string> _FormDataFormat(object PostData) {
            var formdata = new Dictionary<string, string>();
            if (typeof(string) == PostData.GetType())
            {
                foreach (var item in PostData.ToString().Split("&"))
                {
                    var val = item.Split("=");
                    if (val.Length == 2)
                    {
                        formdata.Add(val[0], val[1]);
                    }
                }
            }
            else if (typeof(Dictionary<string, string>) == PostData.GetType())
            {
                formdata = (Dictionary<string, string>)PostData;
            }
            else
            {
                foreach (var item in PostData.GetType().GetProperties())
                {
                    var val = item.GetValue(PostData);
                    if (val != null && val.ToString().IsNotNull())
                    {
                        formdata.Add(item.Name, val.ToString());
                    }
                }
            }

            return formdata;
        }

        /// <summary>
        /// Post 表单方式请求数据
        /// </summary>
        /// <param name="FormData"></param>
        /// <param name="RequestUrl"></param>
        /// <param name="Token"></param>
        /// <param name="TimeOut">超时时间 秒</param>
        /// <returns></returns>
        public static async Task<string> PostFormUrlencoded(Dictionary<string, string> FormData, string RequestUrl ,string Token = null,int TimeOut=1200) {
            var client = new HttpClient();
            try
            {
                //添加请求头
                if (!string.IsNullOrWhiteSpace(Token))
                {
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token);

                }
                client.DefaultRequestHeaders.Accept.Clear();
                var dataurl = "";
                foreach (var item in FormData)
                {
                    dataurl += $"{item.Key}={item.Value}&";
                }
                var content = new StringContent(dataurl);
                content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
                
            client.Timeout = new TimeSpan(0, 0, TimeOut);
                var response = await client.PostAsync(RequestUrl, content);
              
                var html = await response.Content.ReadAsStringAsync();
                client.Dispose();
                response.Dispose();
                return html;
            }
            catch (Exception ex) {
                var message = ex.Message;
                return null;
            }
           
        }

        /// <summary>
        /// Post 表单方式请求数据
        /// </summary>
        /// <param name="FormData"></param>
        /// <param name="RequestUrl"></param>
        /// <param name="FileList">上传的文件列表</param>
        /// <param name="Token"></param>
        /// <param name="TimeOut">超时时间 秒</param>
        /// <returns></returns>
        public static async Task<string> PostForm(Dictionary<string, string> FormData, string RequestUrl, List<PostFileListEntity> FileList = null, string Token = null, int TimeOut = 1200)
        {
            var client = new HttpClient();
            try
            {
                //添加请求头
                if (!string.IsNullOrWhiteSpace(Token))
                {
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token);

                }
                client.DefaultRequestHeaders.Accept.Clear();
                var content = new MultipartFormDataContent();

                foreach (var item in FormData)
                {
                    content.Add(new StringContent(item.Value), item.Key);
                }

                if (FileList != null)
                {
                    foreach (var item in FileList)
                    {
                        content.Add(new StreamContent(item.FileValue, (int)item.FileValue.Length), "file", item.FileName);

                    }
                }
                client.Timeout = new TimeSpan(0, 0, TimeOut);
                var response = await client.PostAsync(RequestUrl, content);

                var html = await response.Content.ReadAsStringAsync();
                client.Dispose();
                response.Dispose();
                return html;
            }
            catch (Exception ex)
            {
                var message = ex.Message;
                return null;
            }

        }

        /// <summary>
        /// Post请求提交Json格式数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="DataDto"></param>
        /// <param name="requestUri"></param>
        /// <param name="token"></param>
        /// <param name="TimeOut">请求超时时间</param>
        /// <param name="JsonNotWebOption">True 时候会采用小驼峰格式方式提交 False 对象原始大小写格式</param>
        /// <returns>options</returns>
        public static async Task<string> PostJson<T>(T DataDto, string requestUri, string token=null, int TimeOut = 1200, bool JsonNotWebOption = true)
        {
           
            var client = new HttpClient();
            try
            {
                //添加请求头
                if (!string.IsNullOrWhiteSpace(token))
                {
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

                }
                client.DefaultRequestHeaders.Accept.Clear();

                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpContent httpContent = JsonContent.Create(DataDto);
                if (JsonNotWebOption)
                {//json序列化格式 默认按照 定义的属性
                    httpContent = JsonContent.Create( DataDto,options:new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
                }
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                client.Timeout = new TimeSpan(0,0,TimeOut);
                HttpResponseMessage response = await client.PostAsync(requestUri, httpContent);
                var html = await response.Content.ReadAsStringAsync();
                client.Dispose();
                response.Dispose();
                return html;
            }
            catch
            {
                return null;
            }
        }
        #endregion

        /// <summary>
        /// 发送Get请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Getdata"></param>
        /// <param name="requestUri"></param>
        /// <param name="token"></param>
        /// <param name="TimeOut">请求超时时间 秒 默认1200秒</param>
        /// <returns></returns>
        public static async Task<string> Get<T>(T Getdata, string requestUri, string token=null,int TimeOut=1200)
        {
           var parameters = new Dictionary<string, string>();
           
            foreach (var item in typeof(T).GetProperties())
            {
                var value = item.GetValue(Getdata);
                if (value != null)
                {
                    parameters.Add(item.Name,value.ToString());
                }
            }
          
            return await Get(parameters, requestUri, token);
        }

        /// <summary>
        /// 公共方法—— 发送http get 请求  2020年6月2日11:22:11  Dennyhui
        /// <para>最终以url参数的方式提交</para>
        /// </summary>
        /// <param name="parameters">参数字典,可为空</param>
        /// <param name="requestUri">例如/api/Files/UploadFile</param>
        /// <param name="TimeOut">请求超时时间 秒</param>
        /// <returns></returns>
        public static async Task<string> Get(Dictionary<string, string> parameters, string requestUri, string token=null,int TimeOut=1200)
        {
            //从工厂获取请求对象
            var client = new HttpClient();
            //添加请求头
            if (!string.IsNullOrWhiteSpace(token))
            {
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
            }
            //拼接地址
            if (parameters != null)
            {
                var strParam = string.Join("&", parameters.Select(o => o.Key + "=" + o.Value));
                requestUri = string.Concat(requestUri, '?', strParam);
            }
            client.BaseAddress = new Uri(requestUri);
            client.Timeout = new TimeSpan(0,0, TimeOut);
            var html= await client.GetStringAsync(requestUri);

            client.Dispose();
            return html;
        }

        /// <summary>
        /// 获取下载http远程文件流
        /// </summary>
        /// <param name="FilepathUrl"></param>
        /// <returns></returns>
        public static async Task<Byte[]> GetUrlFileStream(string FilepathUrl)
        {
            try
            {
               
                HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(FilepathUrl);
                var stream = await client.GetStreamAsync(FilepathUrl);
                //byte[] bytes = new byte[stream.Length];
                // stream.Read(bytes, 0, bytes.Length);
                // return bytes;

                int _fileream = stream.ReadByte();

                List<byte> _btlist = new List<byte>();
                while (_fileream > -1)
                {
                    _btlist.Add((byte)_fileream);
                    _fileream = stream.ReadByte();
                }
                byte[] filebyte = _btlist.ToArray();


                return filebyte;
            }
            catch {
                return null;
            }
        }

        /// <summary>
        /// 下载远程文件到本地
        /// </summary>
        /// <param name="Fileurl"></param>
        /// <param name="SaveFilePath">本地存储地址</param>
        /// <param name="SaveFileName">保存的文件名称</param>
        /// <returns></returns>
        public static async Task<string> FileDown(string Fileurl,string SaveFilePath,string SaveFileName)
        {
            if (SaveFileName.IsNull())
            {
                if (Fileurl.IndexOf('\\') >= 0)
                {
                    var fl = Fileurl.Split('\\');
                    SaveFileName = fl[fl.Length - 1];
                }
                else
                {
                    var fl = Fileurl.Split('/');
                    SaveFileName = fl[fl.Length - 1];
                }
                
            }
            var Filestream=await GetUrlFileStream(Fileurl);
            if (Filestream != null)
            {
                Directory.CreateDirectory(SaveFilePath);
                SaveFileName = SaveFilePath + "/" + SaveFileName;
                using (FileStream filestream = File.Create(SaveFileName))
                {
                    filestream.Write(Filestream);
                    filestream.Close();
                }


            }
            else
            { 
                      SaveFileName = null;
            }

            return SaveFileName;

        }

    }
}
